package com.caltco.cargo.ops.common.base.gen;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caltco.cargo.ops.common.base.BaseEntity;
import com.caltco.cargo.ops.common.exception.RRException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 通用业务实现
 *
 * @author Yaolong
 * @since v1.0.0
 */
@Slf4j
public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements IBaseService<T> {


    @Override
    public boolean create(T domain) {
        return super.save(domain);
    }

    @Override
    public boolean remove(Serializable id) {
        return super.removeById(id);
    }

    @Override
    public boolean update(T domain) {
        try {
            return super.updateById(domain);
        } catch (Exception e) {
            throw new RRException(e.getMessage());
        }
    }

    @Override
    public T get(Serializable id) {
        T domain = super.getById(id);
        if (null == domain) {
            throw new RRException("数据不存在");
        }
        return domain;
    }

    @Override
    public IPage<?> page(int current, int size, T domain) {
        Page<T> page = new Page<>(current, size);
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        return super.page(page, wrapper);
    }


    @Override
    public List<T> list(T domain) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        return super.getBaseMapper().selectList(wrapper);
    }

    @Override
    public boolean removeBatch(List<Serializable> ids) {
        return super.removeBatchByIds(ids);
    }


    @Override
    public boolean exportFile(List<Serializable> ids) {
        //TODO 导出功能开发中
        return false;
    }

    @Override
    public boolean importFile(MultipartFile file, T domain) {
        List<T> list = importFileList(file, domain);
        if (list.isEmpty()) {
            throw new RRException("未解析到数据");
        }
        return saveBatch(list);
    }

    @Override
    public List<T> importFileList(MultipartFile file, T domain){
        List<T> list = new CopyOnWriteArrayList<>();
        try {
            EasyExcel.read(file.getInputStream())// 读取Excel文件
                    .sheet() // 读取哪个sheet，索引从0开始
                    .head(domain.getClass()) // 设置映射对象
                    .headRowNumber(1) // 设置1，因为头值占了一行。如果多行头，就设置几行。索引从1开始
                    .registerReadListener(new AnalysisEventListener<T>() { //注册读的监听器
                        /**
                         * 每解析一行excel数据，就会被调用一次
                         * @param demoData
                         * @param analysisContext
                         */
                        @Override
                        public void invoke(T demoData, AnalysisContext analysisContext) {
                            // 重点在这里，此处设置为false,忽略空白行
                            analysisContext.readWorkbookHolder().setIgnoreEmptyRow(true);
                            list.add(demoData);
                            log.info("解析到一条数据为：{}", JSON.toJSONString(demoData));
                        }

                        /**
                         * 全部解析完被调用
                         * @param analysisContext
                         */
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                            log.info("全部解析完成");
                        }
                    }).doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    protected boolean checkUniqueness(String column, Object value) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        wrapper.eq(column, value);
        System.out.println(super.count(wrapper) > 0);
        return super.count(wrapper) > 0;
    }

    @Override
    public boolean exportTempFile(HttpServletResponse response, T domain) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream(), domain.getClass()).autoCloseStream(Boolean.FALSE).sheet("模板")
                    .doWrite(new ArrayList<>());
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public List<?> getSearch(String search) {
        return List.of();
    }

    @Override
    public boolean saveUploadBatch(List<T> domain) {
        return super.saveOrUpdateBatch(domain);
    }
}
